package com.xuliugen.rpc.registry;

import com.xuliugen.rpc.protocol.InvokerMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xuliugen
 * @date 2018/6/6
 */
public class RegistryHandler extends ChannelInboundHandlerAdapter {

    /**
     * 服务注册Map
     */
    private static ConcurrentHashMap<String, Object> registerMap = new ConcurrentHashMap<>();

    /**
     * 全限定类名：rpc.provider.RpcCalc
     */
    private List<String> classCache = new ArrayList<>();

    /**
     * 服务提供者所在package
     */
    private static final String PROVIDER_SCANNER_PACKAGE = "com.xuliugen.rpc.provider";

    public RegistryHandler() {
        //自动寻找服务提供地址并进行初始化
        scannerClass(PROVIDER_SCANNER_PACKAGE);
        //服务的注册
        doRegister();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        Object result = new Object();
        InvokerMessage request = (InvokerMessage) msg;

        //远程调用发现服务的逻辑
        if (registerMap.containsKey(request.getClassName())) {
            //获取接口名称
            Object clazz = registerMap.get(request.getClassName());
            //代理对象的方法和名称
            Method method = clazz.getClass().getMethod(request.getMethodName(), request.getParamTypes());
            //执行方法调用，返回结果
            result = method.invoke(clazz, request.getParamValues());
        }
        //异步的方式返回给客户端
        ctx.write(result);
        ctx.flush();
        ctx.close();
    }

    /**
     * 服务扫描发现
     * @param packageName
     */
    private void scannerClass(String packageName) {
        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            //如果是一个文件夹，继续递归
            if (file.isDirectory()) {
                scannerClass(packageName + "." + file.getName());
            } else {
                //找到全包类名rpc.provider.RpcCalc
                classCache.add(packageName + "." + file.getName().replace(".class", "").trim());
            }
        }
    }

    /**
     * 注册服务到registerMap中
     */
    private void doRegister() {
        if (classCache.size() == 0) {
            return;
        }
        for (String className : classCache) {
            try {
                Class<?> clazz = Class.forName(className);
                Class<?> interfaces = clazz.getInterfaces()[0];

                //注册服务到registerMap中
                registerMap.put(interfaces.getName(), clazz.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
